package licode.unisop.auth.domain.user.service;

import licode.unisop.auth.application.gateway.UserAuthGateway;
import licode.unisop.auth.client.info.Credential;
import licode.unisop.auth.client.info.UserIdFindIn;
import licode.unisop.auth.domain.user.gateway.UserGateway;
import licode.unisop.auth.exception.AuthErrorCode;
import licode.unisop.client.api.auth.SopUserAuthQuery;
import licode.unisop.client.info.SopTokenInfo;
import licode.unisop.client.info.SopUpdatePasswordIn;
import licode.unisop.client.info.SopUserIdIn;
import licode.unisop.client.vo.SopAuthBrief;
import licode.unisop.client.vo.SopAuthUser;
import licode.unisop.client.vo.SopCredential;
import licode.unisop.client.vo.SopUserBrief;
import licode.unisop.platform.client.api.SiPlatformAuthService;
import licode.unisop.platform.client.vo.PlatAuthVO;
import licode.unisop.provider.info.SiAuthCode;
import licode.unisop.provider.info.SiAuthContextIn;
import licode.unisop.provider.info.SiCodeInfo;
import licode.unisop.provider.info.SiPlatIdFind;
import licode.unisop.provider.utils.StrUtil;
import licode.unisop.provider.vo.SiProps;
import licode.unisop.provider.vo.SiUser;
import licode.unisop.realm.client.info.SiUpdatePasswordIn;
import licode.unisop.types.AuthConst;
import licode.unisop.unilite.result.UniException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * 处理用户认证相关的业务逻辑
 *
 * @author licode
 */
@Service
public class UserAuthService {
    @Resource
    private UserGateway userGateway;

    @Resource
    private UserAuthGateway userAuthGateway;

    @Resource
    private SopUserAuthQuery sopUserAuthQuery;

    @Resource
    private SiPlatformAuthService siPlatformAuthService;

    /**
     * 通过登录信息认证码
     *
     * @param req 登录信息
     * @return 返回认证码
     */
    public SiCodeInfo authorize(SiAuthContextIn req) {
        return userAuthGateway.authorize(req);
    }

    public SiCodeInfo autoSso(SiAuthContextIn auth) {
        return userAuthGateway.autoSso(auth);
    }

    public SopAuthUser token(SiAuthCode codeInfo) {
        SiUser siUser;
        /*
         * 1. 通过授权码生成用户凭证
         */
        Credential credential;

        credential = userAuthGateway.buildAuthInfo(codeInfo);

        /*
         * 通过UserId找到对应的用户
         */
        siUser = userGateway.findUser(UserIdFindIn
                .builder()
                .realmId(credential.getRealmId())
                .userId(credential.getUserId())
                .build());

        return buildAuthUser(siUser, credential);
    }

    /**
     * 通过登录信息直接登录
     *
     * @param req 登录信息
     * @return 返回认证的用户信息
     */
    public SopAuthUser login(SiUser siUser, SiAuthContextIn req) {
        /*
         * 1. 通过认证信息生成用户凭证
         */
        Credential credential;
        credential = userAuthGateway.buildAuthInfo(req);

        if (null == credential) {
            throw AuthErrorCode.BUILD_AUTH_INFO_FAILED.buildThrow();
        }

        return buildAuthUser(siUser, credential);
    }

    private SopAuthUser buildAuthUser(SiUser siUser, Credential credential) {
        SiProps props;
        SopAuthUser authUser;

        if (null == siUser || StrUtil.isBlank(siUser.getId())) {
            throw AuthErrorCode.USER_NOT_EXIST.buildThrow();
        }

        if (null == siUser.getProps()) {
            props = SiProps.EMPTY;
        } else {
            props = siUser.getProps();
        }

        authUser = SopAuthUser.builder()
                .user(SopUserBrief.builder()
                        .userId(siUser.getId())
                        .name(siUser.getName())
                        .gender(props.getString("gender", ""))
                        .avatar(props.getString("avatar", ""))
                        .mobile(props.getString("mobile", ""))
                        .nickName(siUser.getNickName())
                        .props(props)
                        .build())
                .cred(SopCredential.builder()
                        .brief(SopAuthBrief.builder()
                                .userId(credential.getUserId())
                                .userType(credential.getUserType())
                                .account(credential.getAccount())
                                .authType(credential.getAuthType())
                                .roleCodes(credential.getRoleCodes())
                                .roleNames(credential.getRoleNames())
                                .realmId(credential.getRealmId())
                                .clientId(credential.getClientId())
                                .platformId(credential.getPlatformId())
                                .tenantId(credential.getTenantId())
                                .terminalId(credential.getTerminalId())
                                .build())
                        .accessToken(credential.getAccessToken())
                        .accessExpired(credential.getAccessExpired())
                        .refreshToken(credential.getRefreshToken())
                        .refreshExpired(credential.getRefreshExpired())
                        .build())
                .build();

        return authUser;
    }

    /**
     * 根据刷新令牌刷新访问令牌
     *
     * @param tokenInfo 刷新令牌
     * @return 返回重新生成后的认证信息
     */
    public Credential refresh(SopTokenInfo tokenInfo) {
        Credential credential;

        if (StrUtil.isBlank(tokenInfo.getRealmId())) {
            PlatAuthVO platAuth = siPlatformAuthService.fromId(SiPlatIdFind.builder()
                    .platformId(tokenInfo.getPlatformId()).build());
            if (null != platAuth) {
                tokenInfo.setRealmId(platAuth.getRealmId());
            }
        }

        credential = userAuthGateway.refreshAuthInfo(tokenInfo);

        if (null == credential) {
            throw AuthErrorCode.INVALID_REFRESH_TOKEN.buildThrow();
        }
        return credential;
    }

    /**
     * 根据访问令牌退出当前登录
     *
     * @param tokenIdInfo 访问令牌
     */
    public void logout(SopTokenInfo tokenIdInfo) {
        userAuthGateway.logout(tokenIdInfo);
    }

    public void logoutSso(SopTokenInfo tokenIdInfo) {
        userAuthGateway.logoutSso(tokenIdInfo);
    }

    public void logoutUser(SopUserIdIn req) {
        userAuthGateway.logoutUser(req);
    }

    public void logoutSession(SopTokenInfo tokenIdInfo) {
        userAuthGateway.logoutSession(tokenIdInfo);
    }

    public void updatePassword(SopUpdatePasswordIn info) {
        SopAuthBrief authBrief;
        authBrief = sopUserAuthQuery.getAuthBrief(SopTokenInfo.builder()
                .platformId(info.getPlatformId())
                .token(info.getAccessToken())
                .build());
        if (null != authBrief) {
            userGateway.updatePassword(SiUpdatePasswordIn.builder()
                    .realmId(info.getRealmId())
                    .userId(authBrief.getUserId())
                    .oldPwd(info.getOldPwd())
                    .newPwd(info.getNewPwd())
                    .build());
        } else {
            throw new UniException(AuthConst.USER_NOT_LOGIN, "登录已失效！");
        }
    }
}
